

const axios = require("axios");
const Redis = require("ioredis");
const logger = require("../../../utils/logger");
const { publishCallback } = require("../../../utils");

class WeChatTokenManager {
  constructor(appId, appSecret, redisUrl) {
    this.appId = appId;
    this.appSecret = appSecret;
    this.redis = new Redis(redisUrl);
    this.tokenKey = `wechat:access_token:${appId}`;
  }

  async getToken() {
    const token = await this.redis.get(this.tokenKey);
    if (token) {
      return token;
    }
    return this.fetchNewToken();
  }

  async fetchNewToken() {
    const url = `https://api.weixin.qq.com/cgi-bin/stable_token`;

    try {
      const response = await axios.post(url, {
        grant_type: "client_credential",
        appid: this.appId,
        secret: this.appSecret,
      });
      logger.info(JSON.stringify(response.data, null, 2));
      const { access_token, expires_in } = response.data;
      if (!access_token) throw new Error("获取微信access_token失败");
      logger.info(`获取微信access_token成功: ${access_token}`);
      // 确保 expires_in 是一个数字，并且将其转换为整数
      if (typeof expires_in !== "number" || isNaN(expires_in)) {
        throw new Error("Invalid expires_in value from WeChat API");
      }

      // 将过期时间设置为微信返回时间的90%，以确保在实际过期前刷新
      const expirySeconds = Math.floor(expires_in * 0.9);

      // 使用 pipeline 来确保原子性操作
      await this.redis
        .pipeline()
        .set(this.tokenKey, access_token)
        .expire(this.tokenKey, expirySeconds)
        .exec();

      logger.info(`成功获取新的微信 access_token，有效期 ${expirySeconds} 秒`);

      return access_token;
    } catch (error) {
      logger.error(`获取微信access_token失败: ${error}`);
      throw error;
    }
  }
}

const tokenManager = new WeChatTokenManager(
  process.env.WECHAT_APP_ID,
  process.env.WECHAT_APP_SECRET,
  process.env.REDIS_URL
);

//
async function makeAuthorizedRequest(url, method = "GET", data = null) {
  const token = await tokenManager.getToken();
  const config = {
    method,
    url: `${url}?access_token=${token}`,
    data,
  };

  try {
    const response = await axios(config);
    return response.data;
  } catch (error) {
    logger.error(`请求微信接口失败: ${error}`);
    if (error.response && error.response.data.errcode === 40001) {
      // Token可能已过期，尝试刷新
      await tokenManager.fetchNewToken();
      return makeAuthorizedRequest(url, method, data); // 递归调用，使用新token
    }
    throw error;
  }
}
async function getDraftList(page = 1, pageSize = 20) {
  try {
    const url = "https://api.weixin.qq.com/cgi-bin/draft/batchget";
    const data = {
      offset: (page - 1) * pageSize,
      count: pageSize,
      no_content: 0, // 1不返回文章正文，0返回文章正文
    };

    const response = await makeAuthorizedRequest(url, "POST", data);

    if (response.errcode) {
      logger.error(`微信 API 错误：${response.errmsg}`);
      throw new Error(`微信 API 错误：${response.errmsg}`);
    }

    return {
      items: response.item,
      total_count: response.total_count,
      page,
      pageSize,
    };
  } catch (error) {
    logger.error(`获取草稿箱列表失败：${error.message}`);
    throw new Error(`获取草稿箱列表失败：${error.message}`);
  }
}

// 认证中间件
function wechatAuthMiddleware(req, res, next) {
  req.wechatRequest = makeAuthorizedRequest;
  next();
}

// API 端点：获取草稿箱列表
async function getDrafts(req, res) {
  try {
    const { page = 1, pageSize = 20 } = req.query;
    const drafts = await getDraftList(parseInt(page), parseInt(pageSize));
    logger.info(`获取草稿箱列表成功`);
    res.json({ status: "success", code: 200, data: drafts });
  } catch (error) {
    logger.error(`获取草稿箱列表失败: ${error.message}`);
    res
      .status(500)
      .json({ status: "error", code: 500, message: error.message });
  }
}

async function getTagList() {
  try {
    const url = "https://api.weixin.qq.com/cgi-bin/tags/get";

    logger.info("正在获取微信公众号标签列表");
    const response = await makeAuthorizedRequest(url, "GET");

    if (response.errcode) {
      logger.error(
        `微信 API 错误：${response.errmsg} (错误码: ${response.errcode})`
      );
      throw new Error(
        `微信 API 错误：${response.errmsg} (错误码: ${response.errcode})`
      );
    }

    logger.info(
      `成功获取微信公众号标签列表，共 ${response.tags.length} 个标签`
    );
    return {
      tags: response.tags,
      total_count: response.tags.length,
    };
  } catch (error) {
    logger.error(`获取微信公众号标签列表失败：${error.message}`, { error });
    throw new Error(`获取微信公众号标签列表失败：${error.message}`);
  }
}

async function getTags(req, res) {
  try {
    const tags = await getTagList();
    res.json({ status: "success", code: 200, data: tags });
  } catch (error) {
    logger.error(`获取微信公众号标签列表失败: ${error.message}`, {
      error,
      stack: error.stack,
    });
    res.status(500).json({
      status: "error",
      code: 500,
      message: "获取微信公众号标签列表失败，请查看服务器日志以获取更多信息。",
    });
  }
}
// 发布文章,根据标签
// 接口说名： http请求方式: POST https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN
// 返回结果如下：
/***
 * {
   "errcode":0,
   "errmsg":"send job submission success",
   "msg_id":34182, 
   "msg_data_id": 206227730
   }
 */
// #TAG: platform_key 作品id, 获取不到，需要想办法处理
async function publishArticleByTag(req, res) {
  const { media_id, tag_id, post_id: id, task_id = "" } = req.body;
  try {
    const publishResponse = await publish(tag_id, media_id);
    if (publishResponse.errcode) {
      throw new Error(
        `微信 API 错误：${publishResponse.errmsg} (错误码: ${publishResponse.errcode})`
      );
    }

    logger.info(`成功提交文章发布请求，msg_id: ${publishResponse.msg_id}`);
    logger.info(`成功提交文章发布请求，msg_data_id: ${publishResponse.msg_data_id}`);
    logger.info(`发布成功responseData: ${JSON.stringify(publishResponse)}`);

    let pollingResult;
    let status = 4;
    let message = "";
    let platform_key = "";

    try {
      // 开始轮询发布结果
      pollingResult = await pollPublishResult(publishResponse.msg_id);
      status = 3;
      message = "微信公众号文章发布成功";
      platform_key = publishResponse.msg_data_id.toString();
    } catch (pollingError) {
      logger.error(`轮询发布结果失败：${pollingError.message}`);
      message = `微信公众号文章发布失败：${pollingError.message}`;
    }

    // 发送回调通知
    try {
      await publishCallback(id, status, message, task_id, platform_key);
      logger.info(`成功发送回调通知，id: ${id}, status: ${status}`);
    } catch (callbackError) {
      logger.error(`发送回调通知失败：${callbackError.message}`, {
        callbackError,
      });
    }

    if (status === 3) {
      res.json({ status: "success", code: 200, data: pollingResult });
    } else {
      throw new Error(message);
    }
  } catch (error) {
    logger.error(`发布文章失败：${error.message}`, { error });
    publishCallback(id, 4, error.message, task_id, "");
    res.status(500).json({
      status: "error",
      code: 500,
      message: "发布文章失败，请查看服务器日志以获取更多信息。",
    });
  }
}

//发布文章
async function publish(tag_id, media_id) {
  const url = `https://api.weixin.qq.com/cgi-bin/message/mass/sendall`;
  const data = {
    filter: {
      is_to_all: tag_id ? false : true,
    },
    msgtype: "mpnews",
    mpnews: {
      media_id: media_id,
    },
    // 判定为转载文章，是否继续发送，1为继续发送，0为不继续发送
    send_ignore_reprint: 1,
  };

  // 只有当 tag_id 存在时，才添加到 filter 中
  if (tag_id) {
    data.filter.tag_id = tag_id;
  }

  return await makeAuthorizedRequest(url, "POST", data);
}

//轮询发布结果
async function pollPublishResult(msg_id) {
  const maxAttempts = 10;
  const delayBetweenAttempts = 5000; // 5秒

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const result = await publishResultPolling(msg_id);

    if (result.msg_status === "SEND_SUCCESS") {
      logger.info(`文章发布成功，msg_id: ${msg_id}`);
      return result;
    } else if (result.msg_status === "SENDING") {
      logger.info(`文章正在发送中，msg_id: ${msg_id}，尝试次数: ${attempt}`);
      await new Promise((resolve) => setTimeout(resolve, delayBetweenAttempts));
    } else {
      logger.error(
        `文章发布失败，msg_id: ${msg_id}，状态: ${result.msg_status}`
      );
      throw new Error(`文章发布失败，状态: ${result.msg_status}`);
    }
  }

  throw new Error(`轮询超时，无法确认文章发布状态，msg_id: ${msg_id}`);
}

//查询发布结果
async function publishResultPolling(msg_id) {
  const url = `https://api.weixin.qq.com/cgi-bin/message/mass/get`;
  const data = {
    msg_id: msg_id,
  };
  return await makeAuthorizedRequest(url, "POST", data);
}

module.exports = {
  wechatAuthMiddleware,
  getDrafts,
  getDraftList,
  getTags,
  getTagList,
  publishArticleByTag,
};
